package com.dlc.shop.api.controller;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dlc.shop.bean.dto.wukong.*;
import com.dlc.shop.bean.enums.PositionType;
import com.dlc.shop.bean.enums.SendUserTypeEnum;
import com.dlc.shop.bean.model.*;
import com.dlc.shop.bean.vo.wukong.*;
import com.dlc.shop.common.config.Constant;
import com.dlc.shop.common.enums.SysTypeEnum;
import com.dlc.shop.common.exception.YamiShopBindException;
import com.dlc.shop.common.response.ServerResponseEntity;
import com.dlc.shop.common.util.PageParam;
import com.dlc.shop.common.wukongim.constant.WuKongConstant;
import com.dlc.shop.security.common.util.AuthUserContext;
import com.dlc.shop.service.*;
import com.dlc.shop.sys.common.model.ShopEmployee;
import com.dlc.shop.sys.common.model.SysUser;
import com.dlc.shop.sys.common.service.ShopEmployeeService;
import com.dlc.shop.sys.common.service.SysUserService;
import com.dlc.shop.wukongim.service.WuKongImService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author TRACK
 */
@RestController
@AllArgsConstructor
@RequestMapping("/p/wuKongIm")
@Tag(name = "用户客服接口")
public class WuKongImController {

    private final WuKongImService wuKongImService;
    private final ImChannelService imChannelService;

    private final SysUserService sysUserService;
    private final ShopEmployeeService shopEmployeeService;
    private final ShopDetailService shopDetailService;
    private final UserService userService;
    private final ImAutoReplyService imAutoReplyService;
    private final ProductService productService;
    private final ProdBrowseLogService prodBrowseLogService;

    @PostMapping("/registerOrLogin")
    @Operation(summary = "用户注册或登录到im")
    public ServerResponseEntity<RegisterOrLoginVO> registerOrLogin() {
        String uid = AuthUserContext.getUid();
        // 用户客服页面不支持多开消息盒子窗口
        List<String> list = StpUtil.getTokenValueListByLoginId(uid);
        // 使用最开始登录的token
        String token = list.get(0);
        RegisterOrLoginDTO registerOrLoginDTO = new RegisterOrLoginDTO(uid, token, 0);
        wuKongImService.registerOrLogin(registerOrLoginDTO);
        return ServerResponseEntity.success(new RegisterOrLoginVO(uid, token));
    }

    @PostMapping("/createChannel")
    @Operation(summary = "用户与商家/平台创建频道", description = "用户首次发消息时调用")
    @Parameter(name = "shopId", description = "店铺id，平台为0", required = true)
    public ServerResponseEntity<ChannelVO> createChannel(@RequestParam("shopId") Long shopId) {
        String uid = AuthUserContext.getUid();
        String userId = AuthUserContext.getUserId();
        // 频道id，用户id+店铺id
        String channelId = WuKongConstant.getChannelId(userId, shopId);
        List<String> subscribers = new ArrayList<>();
        subscribers.add(uid);
        ChannelDTO channelDTO = new ChannelDTO(channelId, WuKongConstant.GROUP_CHAT, 0, subscribers);
        // 获取店铺订阅者id和组装订阅者
        Long employeeId = getEmployeeIdAndHandleInfo(shopId, channelId, channelDTO);
        // 组装结果
        ChannelVO channelVO = getChannelVO(shopId, channelId, employeeId);
        // 创建频道
        ImChannel imChannel = new ImChannel(channelId, shopId, userId, employeeId);
        imChannelService.createChannel(imChannel, channelDTO, channelVO.getNickName());
        return ServerResponseEntity.success(channelVO);
    }

    @PostMapping("/updateChannel")
    @Operation(summary = "用户与商家/平台更新频道", description = "频道创建过后，最后的聊天人不在线，订阅者更新")
    public ServerResponseEntity<ChannelVO> updateChannel(@RequestBody @Valid ChannelUpdateDTO channelUpdateDTO) {
        String channelId = channelUpdateDTO.getChannelId();
        ImChannel dbChannel = imChannelService.getByChannelId(channelId);
        ChannelVO channelVO = new ChannelVO(channelId);
        Long shopId = WuKongConstant.getShopId(channelId);
        Long employeeId;
        String uid;
        List<Long> dbOnlineStatus = wuKongImService.listOnlineManagerIds(Collections.singletonList(dbChannel.getEmployeeId()), shopId);
        if (CollUtil.isNotEmpty(dbOnlineStatus)) {
            // 当前负责的客服在线，不需要转接
            return ServerResponseEntity.success(channelVO);
        }
        if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            // 原所有订阅客服不在线，转接给其他客服
            List<Long> sysUserIds = sysUserService.listSysUserIds();
            // 检查除当前客服外，其他订阅者的在线情况
            List<Long> onlineSysUserIds = wuKongImService.listOnlineManagerIds(sysUserIds, shopId);
            // 所有客服都不在线，维持原状
            if (CollUtil.isEmpty(onlineSysUserIds)) {
                return ServerResponseEntity.success(channelVO);
            }
            employeeId = getEmployeeId(onlineSysUserIds, Constant.SUPER_ADMIN_ID);
            uid = WuKongConstant.getSysUid(employeeId);
        } else {
            List<ShopEmployee> shopEmployeeList = shopEmployeeService.listEnableEmployee(shopId);
            List<Long> shopEmployeeIds = shopEmployeeList.stream().map(ShopEmployee::getEmployeeId).collect(Collectors.toList());
            // 超管
            ShopEmployee admin = shopEmployeeList.stream().filter(user -> Objects.equals(user.getType(), PositionType.ADMIN.value())).toList().get(0);
            List<Long> onlineShopEmployeeIds = wuKongImService.listOnlineManagerIds(shopEmployeeIds, shopId);
            // 所有客服都不在线，维持原状
            if (CollUtil.isEmpty(onlineShopEmployeeIds)) {
                return ServerResponseEntity.success(channelVO);
            }
            employeeId = getEmployeeId(onlineShopEmployeeIds, admin.getEmployeeId());
            uid = WuKongConstant.getShopUid(employeeId, shopId);
        }
        // 组装结果
        channelVO = getChannelVO(shopId, channelId, employeeId);
        // 更新
        ImChannel imChannel = new ImChannel(channelId, shopId, AuthUserContext.getUserId(), employeeId);
        imChannelService.updateChannel(imChannel, uid, channelVO.getNickName());
        return ServerResponseEntity.success(channelVO);
    }

    @GetMapping("/conversation/sync/page")
    @Operation(summary = "分页获取用户最近会话列表")
    public ServerResponseEntity<IPage<ConversationSyncVO>> conversationSyncPage(PageParam<ConversationSyncVO> pageParam, ConversationSyncDTO conversationSyncDTO) {
        conversationSyncDTO.setUid(AuthUserContext.getUid());
        conversationSyncDTO.setMsg_count(1);
        List<ConversationSyncVO> conversationSyncList = wuKongImService.conversationSync(conversationSyncDTO);
        IPage<ConversationSyncVO> page = new PageParam<>();
        page.setTotal(conversationSyncList.size());
        page.setSize(pageParam.getSize());
        page.setCurrent(pageParam.getCurrent());
        long totalPages = page.getTotal() % pageParam.getSize() == 0 ?
                page.getTotal() / pageParam.getSize() : (page.getTotal() / pageParam.getSize() + 1);
        page.setPages(totalPages);
        page.setRecords(new ArrayList<>());
        if (CollUtil.isNotEmpty(conversationSyncList)) {
            int start = Math.min((int)(pageParam.getSize() * (pageParam.getCurrent() - 1)), conversationSyncList.size());
            int end = Math.min(start + (int)pageParam.getSize(), conversationSyncList.size());
            List<ConversationSyncVO> subList = new ArrayList<>();
            if (start < end) {
                subList = conversationSyncList.subList(start, end);
            }
            if (CollUtil.isNotEmpty(subList)) {
                for (ConversationSyncVO conversationSyncVO : subList) {
                    String channelId = conversationSyncVO.getChannelId();
                    Long shopId = WuKongConstant.getShopId(channelId);
                    conversationSyncVO.setShopId(shopId);
                    if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
                        conversationSyncVO.setShopName(Constant.PLATFORM_SHOP_NAME);
                    } else {
                        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(shopId);
                        if (Objects.nonNull(shopDetail)) {
                            conversationSyncVO.setShopName(shopDetail.getShopName());
                            conversationSyncVO.setPic(shopDetail.getShopLogo());
                        }
                    }
                }
            }
            page.setRecords(subList);
        }
        return ServerResponseEntity.success(page);
    }

    @PostMapping("/conversations/setUnread")
    @Operation(summary = "标记频道为已读", description = "点进频道时请求")
    public ServerResponseEntity<Void> setUnread(@RequestBody @Valid SetUnreadDTO setUnreadDTO) {
        if (Objects.isNull(setUnreadDTO.getMaxSeq())) {
            throw new YamiShopBindException("已读的最大消息序号不能为空");
        }
        setUnreadDTO.setUid(AuthUserContext.getUid());
        setUnreadDTO.setUnread(0);
        setUnreadDTO.setChannel_type(WuKongConstant.GROUP_CHAT);
        imChannelService.setUnread(setUnreadDTO, SysTypeEnum.ORDINARY.value());
        return ServerResponseEntity.success();
    }

    @PostMapping("/getShopChannelInfo")
    @Operation(summary = "获取用户与商家的频道信息")
    public ServerResponseEntity<ChannelVO> getShopChannelInfo(@RequestParam(value = "shopId") Long shopId) {
        ImChannel imChannel = imChannelService.getByChannelId(WuKongConstant.getChannelId(AuthUserContext.getUserId(), shopId));
        if (Objects.isNull(imChannel)) {
            return ServerResponseEntity.success();
        }
        ChannelVO channelVO = getChannelVO(shopId, imChannel.getChannelId(), imChannel.getEmployeeId());
        channelVO.setImChannel(imChannel);
        return ServerResponseEntity.success(channelVO);
    }

    @PostMapping("/channel/messageSync")
    @Operation(summary = "获取用户频道消息列表")
    public ServerResponseEntity<MessageSyncVO> messageSync(@RequestBody @Valid MessageSyncDTO messageSyncDTO) {
        Long shopId = WuKongConstant.getShopId(messageSyncDTO.getChannel_id());
        messageSyncDTO.setLogin_uid(AuthUserContext.getUid());
        messageSyncDTO.setChannel_type(WuKongConstant.GROUP_CHAT);
        MessageSyncVO messageSyncVO = wuKongImService.messageSync(messageSyncDTO);
        return ServerResponseEntity.success(messageSyncVO);
    }

    @GetMapping("/listChannelSubcribers")
    @Operation(summary = "获取用户频道订阅者信息", description = "放进channelInfo")
    public ServerResponseEntity<ImChannelVO> listChannelSubcribers(@RequestParam("channelId") String channelId) {
        Long shopId = WuKongConstant.getShopId(channelId);
        String userId = AuthUserContext.getUserId();
        ImChannel imChannel = imChannelService.getByChannelId(channelId);
        if (Objects.isNull(imChannel)) {
            throw new YamiShopBindException("频道不存在");
        }
        if (!Objects.equals(imChannel.getUserId(), userId)) {
            throw new YamiShopBindException("当前频道不属于你");
        }
        ImChannelVO imChannelVO = new ImChannelVO();
        imChannelVO.setChannelId(imChannel.getChannelId());
        imChannelVO.setShopId(shopId);
        List<Long> subscribers = Arrays.stream(imChannel.getSubscribers().split(StrUtil.COMMA))
                .map(id -> Long.parseLong(id)).collect(Collectors.toList());
        List<SubscriberVO> result = new ArrayList<>(subscribers.size());
        List<Long> listOnlineManagerIds = wuKongImService.listOnlineManagerIds(subscribers, shopId);
        if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            imChannelVO.setShopName(Constant.PLATFORM_SHOP_NAME);
            for (Long subscriber : subscribers) {
                SysUser sysUser = sysUserService.getSysUserById(subscriber);
                if (Objects.isNull(sysUser)) {
                    continue;
                }
                SubscriberVO subscriberVO = new SubscriberVO();
                subscriberVO.setShopId(shopId);
                subscriberVO.setUid(WuKongConstant.getSysUid(subscriber));
                subscriberVO.setNickName(sysUser.getNickName());
                subscriberVO.setIsWhiteListUser(Objects.equals(imChannel.getEmployeeId(), subscriber) ? 1 : 0);
                subscriberVO.setIsOnline(listOnlineManagerIds.contains(subscriber) ? 1 : 0);
                subscriberVO.setSendUserType(SendUserTypeEnum.PLATFORM.value());
                subscriberVO.setStatus(sysUser.getStatus());
                result.add(subscriberVO);
            }
        } else {
            ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(shopId);
            imChannelVO.setShopName(shopDetail.getShopName());
            for (Long subscriber : subscribers) {
                ShopEmployee shopEmployee = shopEmployeeService.getShopEmployeeById(subscriber);
                SubscriberVO subscriberVO = new SubscriberVO();
                if (Objects.isNull(shopEmployee)) {
                    continue;
                }
                subscriberVO.setShopId(shopId);
                subscriberVO.setUid(WuKongConstant.getShopUid(subscriber, shopId));
                subscriberVO.setPic(shopDetail.getShopLogo());
                subscriberVO.setIsWhiteListUser(Objects.equals(imChannel.getEmployeeId(), subscriber) ? 1 : 0);
                subscriberVO.setIsOnline(listOnlineManagerIds.contains(subscriber) ? 1 : 0);
                subscriberVO.setSendUserType(SendUserTypeEnum.MULTISHOP.value());
                subscriberVO.setStatus(shopEmployee.getStatus());
                subscriberVO.setNickName(shopEmployee.getNickname());
                result.add(subscriberVO);
            }
        }
        // 组装用户信息
        User user = userService.getUserByUserId(userId);
        SubscriberVO subscriberVO = new SubscriberVO(AuthUserContext.getUid(), user.getNickName(), user.getPic(), 1, 1, SendUserTypeEnum.ORDINARY.value());
        result.add(subscriberVO);
        imChannelVO.setSubscribers(result);
        return ServerResponseEntity.success(imChannelVO);
    }

    @PostMapping("/sendAutoReply")
    @Operation(summary = "发送自动回复")
    @Parameter(name = "channelId", description = "频道id", required = true)
    public ServerResponseEntity<Void> sendAutoReply(@RequestParam(value = "channelId") String channelId) {
        String userId = AuthUserContext.getUserId();
        if (!Objects.equals(WuKongConstant.getUserId(channelId), userId)) {
            throw new YamiShopBindException("当前频道不属于你");
        }
        // 自动回复规则：
        // 当天首次咨询，自动回复一次
        // 完成一次自动回复后，需要人工进行回复后，再次无客服在线，用户再次咨询才可执行下一次的自动回复
        Long shopId = WuKongConstant.getShopId(channelId);
        ImAutoReply imAutoReply = imAutoReplyService.getByShopId(shopId);
        if (Objects.isNull(imAutoReply)) {
            return ServerResponseEntity.success();
        }
        if (Objects.equals(imAutoReply.getStatus(), 0)) {
            // 不启用自动回复
            return ServerResponseEntity.success();
        }
        String uid = getUid(shopId, channelId);
        imChannelService.updateAuto(channelId, 1, imAutoReply.getContent(), uid);
        return ServerResponseEntity.success();
    }

    @PostMapping("/sendAutoReplyContent")
    @Operation(summary = "发送自动回复内容")
    public ServerResponseEntity<Void> sendAutoReplyContent(@RequestBody @Valid SendAutoReplyDTO sendAutoReplyDTO) {
        String channelId = sendAutoReplyDTO.getChannelId();
        String userId = AuthUserContext.getUserId();
        if (!Objects.equals(WuKongConstant.getUserId(channelId), userId)) {
            throw new YamiShopBindException("当前频道不属于你");
        }
        Long shopId = WuKongConstant.getShopId(channelId);
        String uid = getUid(shopId, channelId);
        imChannelService.updateAuto(channelId, 1, sendAutoReplyDTO.getContent(), uid);
        return ServerResponseEntity.success();
    }

    @GetMapping("/recentBrowse")
    @Operation(summary = "最近浏览的商品" , description = "获取最近浏览的商品")
    public ServerResponseEntity<List<Product>> recentBrowse(Long shopId, PageParam<ProdBrowseLog> pageParam) {
        String userId = AuthUserContext.getUserId();
        Page<ProdBrowseLog> prodBrowseLogPage;
        if(Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            prodBrowseLogPage = prodBrowseLogService.page(pageParam, new LambdaQueryWrapper<ProdBrowseLog>()
                    .eq(ProdBrowseLog::getUserId, userId).orderByDesc(ProdBrowseLog::getProdBrowseLogId));
        }else {
            prodBrowseLogPage = prodBrowseLogService.page(pageParam, new LambdaQueryWrapper<ProdBrowseLog>()
                    .eq(ProdBrowseLog::getUserId, userId).eq(ProdBrowseLog::getShopId, shopId).orderByDesc(ProdBrowseLog::getProdBrowseLogId));
        }
        Set<Long> visitProdIdSet = new HashSet<>();
        for (ProdBrowseLog prodBrowseLog : prodBrowseLogPage.getRecords()) {
            visitProdIdSet.add(prodBrowseLog.getProdId());
        }
        if (CollectionUtil.isEmpty(visitProdIdSet)) {
            return ServerResponseEntity.success(Collections.emptyList());
        }
        List<Product> productList = productService.getProductListBySpuIds(visitProdIdSet);
        return ServerResponseEntity.success(productList);
    }

    private String getUid(Long shopId, String channelId) {
        String uid;
        Long employeeId = imChannelService.getByChannelId(channelId).getEmployeeId();
        if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            uid = WuKongConstant.getSysUid(employeeId);
        } else {
            uid = WuKongConstant.getShopUid(employeeId, shopId);
        }
        return uid;
    }

    private static Long getEmployeeId(List<Long> onlineIds, Long superAdminId) {
        Long employeeId;
        if (onlineIds.contains(superAdminId)) {
            // 超管在线转接给超管
            employeeId = superAdminId;
        } else {
            // 随机选择在线客服转接
            int index = (int) (Math.random() * onlineIds.size());
            employeeId = onlineIds.get(index);
        }
        return employeeId;
    }

    private Long getEmployeeIdAndHandleInfo(Long shopId, String channelId, ChannelDTO channelDTO) {
        Long employeeId;
        List<String> subscribers = channelDTO.getSubscribers();
        // 检查在线客服，超管在线给超管，超管不在线随机给其他客服，都不在线默认超管
        if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            List<Long> sysUserIds = sysUserService.listSysUserIds();
            List<Long> onlineSysUserIds = wuKongImService.listOnlineManagerIds(sysUserIds, shopId);
            if (CollUtil.isEmpty(onlineSysUserIds) || onlineSysUserIds.contains(Constant.SUPER_ADMIN_ID)) {
                employeeId = Constant.SUPER_ADMIN_ID;
            } else {
                int index = (int) (Math.random() * onlineSysUserIds.size());
                employeeId = onlineSysUserIds.get(index);
                subscribers.add(WuKongConstant.getSysUid(employeeId));
            }
            // 非超管加入订阅者，要把超管也加入
            subscribers.add(WuKongConstant.getSysUid(Constant.SUPER_ADMIN_ID));
        } else {
            List<ShopEmployee> shopEmployeeList = shopEmployeeService.listEnableEmployee(shopId);
            List<Long> shopEmployeeIds = shopEmployeeList.stream().map(ShopEmployee::getEmployeeId).collect(Collectors.toList());
            // 超管
            ShopEmployee admin = shopEmployeeList.stream().filter(user -> Objects.equals(user.getType(), PositionType.ADMIN.value())).toList().get(0);
            List<Long> onlineShopEmployeeIds = wuKongImService.listOnlineManagerIds(shopEmployeeIds, shopId);
            if (CollUtil.isEmpty(onlineShopEmployeeIds) || onlineShopEmployeeIds.contains(admin.getEmployeeId())) {
                employeeId = admin.getEmployeeId();
            } else {
                int index = (int) (Math.random() * onlineShopEmployeeIds.size());
                employeeId = onlineShopEmployeeIds.get(index);
                subscribers.add(WuKongConstant.getShopUid(employeeId, shopId));
            }
            // 非超管加入订阅者，要把超管也加入
            subscribers.add(WuKongConstant.getShopUid(admin.getEmployeeId(), shopId));
        }
        return employeeId;
    }

    private ChannelVO getChannelVO(Long shopId, String channelId, Long employeeId) {
        ChannelVO channelVO = new ChannelVO(channelId);
        if (Objects.equals(shopId, Constant.PLATFORM_SHOP_ID)) {
            channelVO.setUid(WuKongConstant.getSysUid(employeeId));
            channelVO.setShopName(Constant.PLATFORM_SHOP_NAME);
            SysUser sysUser = sysUserService.getSysUserById(employeeId);
            if (Objects.nonNull(sysUser)) {
                channelVO.setNickName(sysUser.getNickName());
            }
        } else {
            channelVO.setUid(WuKongConstant.getShopUid(employeeId, shopId));
            ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(shopId);
            if (Objects.nonNull(shopDetail)) {
                channelVO.setShopName(shopDetail.getShopName());
                channelVO.setNickName(shopDetail.getShopName());
                channelVO.setPic(shopDetail.getShopLogo());
                channelVO.setShopStatus(shopDetail.getShopStatus());
            }
            ShopEmployee shopEmployee = shopEmployeeService.getShopEmployeeById(employeeId);
            if (Objects.nonNull(shopEmployee)) {
                channelVO.setNickName(shopEmployee.getNickname());
            }
        }
        return channelVO;
    }
}
